package club.xcgame520.okhttpdemo;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.TimeUnit;

import club.xcgame520.okhttp.OkHttp;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 断点续传上传任务，与后台代码必须对应
 */
public class TaskUploadContinue {

    private final static String URL_SERVER = "http://218.77.106.72:18080";

    private final static String URL_CHECK = URL_SERVER + "/shdx_wrj/app/drone/getUploadBlockInfo";
    private final static String URL_UPLOAD = URL_SERVER + "/shdx_wrj/app/drone/blockUploadProcess";
    private final static String URL_CONFIRM = URL_SERVER + "/shdx_wrj/app/drone/blockUploadComplete";

    private OkHttpClient client;

    private Context context;

    private String username;

    private File uploadFile;

    private SharedPreferences preferences;
    private SharedPreferences.Editor editor;

    private Call currentCall;

    private TaskListener taskListener;

    public Context getContext() {
        return context;
    }

    public TaskUploadContinue(Context context) {

        this.context = context;
        client = new OkHttpClient.Builder().
                connectTimeout(15, TimeUnit.SECONDS).
                readTimeout(30, TimeUnit.SECONDS).
                writeTimeout(30, TimeUnit.SECONDS)
                .build();

        preferences = context.getSharedPreferences("taskUpload", Context.MODE_PRIVATE);
        editor = preferences.edit();
    }

    /**
     * @param connectTimeout 连接超时（秒钟）
     */
    public TaskUploadContinue(Context context, int connectTimeout, int readTimeout, int writeTimeout) {
        this.context = context;

        client = new OkHttpClient.Builder().connectTimeout(connectTimeout, TimeUnit.SECONDS).readTimeout(readTimeout, TimeUnit.SECONDS).
                writeTimeout(writeTimeout, TimeUnit.SECONDS).build();

        preferences = context.getSharedPreferences("taskUpload", Context.MODE_PRIVATE);
        editor = preferences.edit();

    }

    public void configTask(String username, File uploadFile) {

        this.username = username;
        this.uploadFile = uploadFile;

    }

    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });

    public void start() {

        if (!uploadFile.exists() || !uploadFile.isFile()) {
            return;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {

                    Log.d("xiaocan", "任务开始");
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (taskListener != null) {
                                taskListener.onStart();
                            }
                        }
                    });

                    boolean isUploadSuccess = true;
                    while (isUploadSuccess) {
                        final UploadBlockInfo uploadBlockInfo = getUploadBlockInfo();
                        final byte[] uploadBlock = getUploadBlock(uploadFile, uploadBlockInfo.uploadBlockIndex, uploadBlockInfo.uploadBlockLength);
                        if (uploadBlock != null) {

                            isUploadSuccess = blockUploadProcess(uploadBlockInfo, uploadBlock);

                            Log.d("xiaocan", "任务进度：" + uploadBlockInfo.uploadBlockIndex);
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (taskListener != null) {
                                        taskListener.onProgress(uploadBlockInfo.uploadBlockIndex);
                                    }
                                }
                            });

                        } else {
                            final String result = confirmComplete(uploadBlockInfo);
                            editor.remove(uploadFile.getPath());
                            editor.commit();

                            Log.d("xiaocan", "任务完成");
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (taskListener != null) {
                                        taskListener.onFinish();
                                        taskListener.onSuccess(result);
                                    }
                                }
                            });

                            break;

                        }
                    }

                } catch (final Exception e) {
                    e.printStackTrace();

                    if (currentCall.isCanceled()) {

                        Log.d("xiaocan", "任务取消");
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                if (taskListener != null) {
                                    taskListener.onFinish();
                                    taskListener.onCancel();
                                }
                            }
                        });

                    } else {

                        Log.d("xiaocan", "任务出错");
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                if (taskListener != null) {
                                    taskListener.onFinish();
                                    taskListener.onFailure(e.getMessage());
                                }
                            }
                        });

                    }


                }

            }
        }).start();


    }

    public void stop() {
        currentCall.cancel();
    }


    private String getUploadFileTag() {

        String value = preferences.getString(uploadFile.getPath(), "");
        if (value.equals("")) {
            String fileTag = username + "_" + System.currentTimeMillis() + "_" + uploadFile.getName();
            editor.putString(uploadFile.getPath(), fileTag);
            editor.commit();
            return fileTag;
        }
        return value;

    }

    private UploadBlockInfo getUploadBlockInfo() throws Exception {

        FormBody.Builder builder = new FormBody.Builder();
        builder.add("fileTag", getUploadFileTag());
        builder.add("fileLength", String.valueOf(uploadFile.length()));

        Request request = new Request.Builder().url(URL_CHECK).post(builder.build()).build();
        currentCall = client.newCall(request);

        Response response = currentCall.execute();
        if (response.isSuccessful()) {
            String result = response.body().string();
            JSONObject jsonResult = new JSONObject(result);
            UploadBlockInfo uploadBlockInfo = new UploadBlockInfo();
            uploadBlockInfo.uploadBlockId = jsonResult.getString("uploadBlockId");
            uploadBlockInfo.uploadBlockIndex = jsonResult.getInt("uploadBlockIndex");
            uploadBlockInfo.uploadBlockName = jsonResult.getString("uploadBlockName");
            uploadBlockInfo.uploadBlockLength = jsonResult.getInt("uploadBlockLength");
            uploadBlockInfo.fileNameSuffix = jsonResult.getString("fileNameSuffix");
            return uploadBlockInfo;
        }
        return null;

    }

    private boolean blockUploadProcess(UploadBlockInfo uploadBlockInfo, byte[] uploadBlock) throws Exception {

        if (uploadBlock != null) {

            MultipartBody.Builder builder = new MultipartBody.Builder();
            builder.setType(MultipartBody.FORM);

            builder.addFormDataPart("uploadBlockId", uploadBlockInfo.uploadBlockId);

            RequestBody requestBody = RequestBody.create(MediaType.parse("*/*"), uploadBlock);
            builder.addFormDataPart("file", uploadBlockInfo.uploadBlockName, requestBody);

            Request request = new Request.Builder().url(URL_UPLOAD).post(builder.build()).build();
            currentCall = client.newCall(request);

            Response response = currentCall.execute();
            if (response.isSuccessful()) {
                return true;
            }

        }

        return false;

    }

    private String confirmComplete(UploadBlockInfo uploadBlockInfo) throws Exception {

        FormBody.Builder builder = new FormBody.Builder();
        builder.add("uploadBlockId", uploadBlockInfo.uploadBlockId);
        builder.add("fileNameSuffix", uploadBlockInfo.fileNameSuffix);

        Request request = new Request.Builder().url(URL_CONFIRM).post(builder.build()).build();
        currentCall = client.newCall(request);

        Response response = currentCall.execute();
        if (response.isSuccessful()) {
            String result = response.body().string();
            return result;
        }
        return null;

    }


    /**
     * @param file      文件
     * @param offset    分页
     * @param blockSize
     * @return
     */
    private static byte[] getUploadBlock(File file, int offset, int blockSize) {
        byte[] result = new byte[blockSize];
        RandomAccessFile accessFile = null;
        try {
            accessFile = new RandomAccessFile(file, "r");
            accessFile.seek(offset * blockSize);
            int readSize = accessFile.read(result);
            if (readSize == -1) {
                return null;
            } else if (readSize == blockSize) {
                return result;
            } else {
                byte[] tmpByte = new byte[readSize];
                System.arraycopy(result, 0, tmpByte, 0, readSize);
                return tmpByte;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (accessFile != null) {
                try {
                    accessFile.close();
                } catch (IOException e1) {
                }
            }
        }
        return null;
    }

    public class UploadBlockInfo {
        String uploadBlockId;
        int uploadBlockIndex;
        String uploadBlockName;
        int uploadBlockLength;
        String fileNameSuffix;
    }

    public class TaskListener {

        public void onStart() {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传开始");
            }
        }

        public void onFailure(String des) {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传失败，原因：" + des);
            }
        }

        public void onSuccess(String response) {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传成功：" + response);
            }
        }

        public void onFinish() {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传结束");
            }
        }

        public void onProgress(int progress) {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传进度：" + progress);
            }
        }

        public void onCancel() {
            if (OkHttp.isPrintLog) {
                Log.d(OkHttp.TAG, "文件上传取消");
            }
        }

    }

}
